import React from "react";
import createReactClass from "create-react-class";
import PropTypes from "prop-types";
import { withTranslation } from "react-i18next";
import Icon from "../Icon.jsx";
import Styles from "./splitter.scss";

import ObserveModelMixin from "../ObserveModelMixin";

// Feature detect support for passive: true in event subscriptions.
// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
let passiveSupported = false;
try {
  const options = Object.defineProperty({}, "passive", {
    get: function() {
      passiveSupported = true;
      return true;
    }
  });

  window.addEventListener("test", null, options);
  window.removeEventListener("test", null, options);
} catch (err) {}

const notPassive = passiveSupported ? { passive: false } : false;

const Splitter = createReactClass({
  displayName: "Splitter",
  mixins: [ObserveModelMixin],

  propTypes: {
    terria: PropTypes.object.isRequired,
    thumbSize: PropTypes.number,
    padding: PropTypes.number,
    t: PropTypes.func.isRequired
  },

  getDefaultProps() {
    return {
      thumbSize: 42,
      padding: 0
    };
  },

  componentDidMount() {
    const that = this;
    window.addEventListener("resize", function() {
      that.forceRefresh();
    });
  },

  componentWillUnmount() {
    this.unsubscribe();
  },

  forceRefresh() {
    const smallChange =
      this.props.terria.splitPosition < 0.5 ? 0.0001 : -0.0001; // Make sure never <0 or >1.
    this.props.terria.splitPosition += smallChange;
  },

  startDrag(event) {
    const viewer = this.props.terria.currentViewer;
    viewer.pauseMapInteraction();

    // While dragging is in progress, subscribe to document-level movement and up events.
    document.addEventListener("mousemove", this.drag, notPassive);
    document.addEventListener("touchmove", this.drag, notPassive);
    document.addEventListener("mouseup", this.stopDrag, notPassive);
    document.addEventListener("touchend", this.stopDrag, notPassive);

    event.preventDefault();
    event.stopPropagation();
  },

  drag(event) {
    let clientX = event.clientX;
    let clientY = event.clientY;
    if (event.targetTouches && event.targetTouches.length > 0) {
      clientX = event.targetTouches.item(0).clientX;
      clientY = event.targetTouches.item(0).clientY;
    }

    const viewer = this.props.terria.currentViewer;

    const container = viewer.getContainer();
    const mapRect = container.getBoundingClientRect();

    const that = this;
    function computeSplitFraction(startBound, endBound, position) {
      const difference = endBound - startBound;
      const fraction = (position - startBound) / difference;

      const min = startBound + that.props.padding + that.props.thumbSize * 0.5;
      const max = endBound - that.props.padding - that.props.thumbSize * 0.5;
      const minFraction = (min - startBound) / difference;
      const maxFraction = (max - startBound) / difference;

      return Math.min(maxFraction, Math.max(minFraction, fraction));
    }
    let splitFractionX = computeSplitFraction(
      mapRect.left,
      mapRect.right,
      clientX
    );
    let splitFractionY = computeSplitFraction(
      mapRect.top,
      mapRect.bottom,
      clientY
    );

    // We compute the maximum and minium windows bounds as a percentage so that we can always apply the bounds
    // restriction as a percentage for consistency (we currently use absolute values for X and percentage values for
    // Y, but always apply the constraint as a percentage).
    // We use absolute pixel values for horizontal restriction because of the fixed UI elements which occupy an
    // absolute amount of screen relestate and 100 px seems like a fine amount for the current UI.
    const minX = computeSplitFraction(
      mapRect.left,
      mapRect.right,
      mapRect.left + 100
    );
    const maxX = computeSplitFraction(
      mapRect.left,
      mapRect.right,
      mapRect.right - 100
    );
    // Resctrict to within +/-30% of the center vertically (so we don't run into the top and bottom UI elements).
    const minY = 0.2;
    const maxY = 0.8;

    splitFractionX = Math.min(maxX, Math.max(minX, splitFractionX));
    splitFractionY = Math.min(maxY, Math.max(minY, splitFractionY));

    this.props.terria.splitPosition = splitFractionX;
    this.props.terria.splitPositionVertical = splitFractionY;

    event.preventDefault();
    event.stopPropagation();
  },

  stopDrag(event) {
    this.unsubscribe();

    const viewer = this.props.terria.currentViewer;
    viewer.resumeMapInteraction();

    event.preventDefault();
    event.stopPropagation();
  },

  unsubscribe() {
    document.removeEventListener("mousemove", this.drag, notPassive);
    document.removeEventListener("touchmove", this.drag, notPassive);
    document.removeEventListener("mouseup", this.stopDrag, notPassive);
    document.removeEventListener("touchend", this.stopDrag, notPassive);
    window.removeEventListener("resize", this.forceRefresh);
  },

  getPosition() {
    const canvasWidth = this.props.terria.currentViewer.getContainer()
      .clientWidth;
    const canvasHeight = this.props.terria.currentViewer.getContainer()
      .clientHeight;
    return {
      x: this.props.terria.splitPosition * canvasWidth,
      y: this.props.terria.splitPositionVertical * canvasHeight
    };
  },

  render() {
    if (
      !this.props.terria.showSplitter ||
      !this.props.terria.currentViewer.canShowSplitter ||
      !this.props.terria.currentViewer.getContainer()
    ) {
      return null;
    }

    const thumbWidth = this.props.thumbSize;
    const position = this.getPosition();

    const dividerStyle = {
      left: position.x + "px",
      backgroundColor: this.props.terria.baseMapContrastColor
    };

    const thumbStyle = {
      left: position.x + "px",
      top: position.y + "px",
      width: thumbWidth + "px",
      height: thumbWidth + "px",
      marginLeft: "-" + thumbWidth * 0.5 + "px",
      marginTop: "-" + thumbWidth * 0.5 + "px",
      lineHeight: thumbWidth - 2 + "px",
      borderRadius: thumbWidth * 0.5 + "px",
      fontSize: thumbWidth - 12 + "px"
    };

    const { t } = this.props;

    return (
      <div>
        <div className={Styles.dividerWrapper}>
          <div className={Styles.divider} style={dividerStyle} />
        </div>
        <button
          className={Styles.thumb}
          style={thumbStyle}
          onClick={e => e.preventDefault()}
          onMouseDown={this.startDrag}
          onTouchStart={this.startDrag}
          title={t("splitterTool.title")}
        >
          <Icon glyph={Icon.GLYPHS.splitter} />
        </button>
      </div>
    );
  }
});

module.exports = withTranslation()(Splitter);
